// 逻辑运算 > < = 操作
// 碰到逻辑元素安抚，需要运行进行想就啊了
package stack_opt

import (
	"Yasuo/iface/istack_opt"
	"Yasuo/iface/iyasuo"
	"Yasuo/utils"
	"errors"
	"fmt"
	"github.com/xuri/efp"
)

// 逻辑运算符工厂
func FactoryLogic(s string) istack_opt.IStackOpt  {
	var (
		m map[string]istack_opt.IStackOpt
	)

	m = make(map[string]istack_opt.IStackOpt)
	// "="
	equal := "="
	m[equal] = NewLogicEqual()
	return m[s]
}

type LoginReal struct{
	tokenValue string
}

func NewLogicReal(tv string) *LoginReal {
	return &LoginReal{
		tokenValue:tv,
	}
}

func (l *LoginReal) InventedOpt(iys iyasuo.IYasuo) error {
	var (
		u *utils.Utils
		err error
	)
	u = utils.NewUtils()
	if u.PushBack(iys.GetLogicOPT(), l.tokenValue); err != nil {
		return err
	}

	// 设置下一个运行的指针
	iys.SetNext(iys.GetNext() + 1)

	return nil
}

// 遇到等于号 =
type LogicEqual struct{}

func NewLogicEqual() *LogicEqual {
	return &LogicEqual{}
}

// 1. 弹出来上一个opd
// 2. 一直for，直到碰到空格变量
// 3. 计算
func (LogicEqual) InventedOpt(iys iyasuo.IYasuo) error {
	var (
		next int
		tokens []efp.Token
		err error
		ok bool
		u *utils.Utils
		oneVarOPD interface{}
		foneVarOPD float64
		tv string
		ii istack_opt.IStackOpt
		sopt string
		leftVarIndex int //  = 左边的变量位置
		leftVar      string // = 左边的变量标识
	)

	u = utils.NewUtils()
	next = iys.GetNext()
	tokens = iys.GetTokens()
	leftVarIndex = next - 1
	leftVar = tokens[leftVarIndex].TValue

	// 1. 弹出来上一个opd,等于号入操作符栈
	// 此时的next是 = 位置
	if _, err = u.RemoveLast(iys.GetOPD()); err != nil {
		fmt.Println("出栈错误")
		return err
	}
	u.PushBack(iys.GetOPT(), "=")

	// 2. 一直for，直到碰到空格变量
	// 遇到啥都放放进公共工厂
	// 一会根据next找到左边的角标
	// 函数跳出后， next 是在空格的位置
	for {
		// 中间的tv处理
		// 此时 next 是 = 后边第一个元素位置
		next+=1
		iys.SetNext(next)
		tv = tokens[next].TValue
		fmt.Println("tv", tv)
		if tokens[next].TType == efp.TokenTypeOperatorInfix && tokens[next].TSubType == efp.TokenSubTypeIntersection {
			break
		}

		//fmt.Println("for中------------------")
		if ii, err = FactoryStackOpt(tokens[next]); err != nil {
			return err
		}
		if err = ii.InventedOpt(iys); err != nil {
			return err
		}
		//fmt.Println("for---------------end")
		//next++
	}

	fmt.Println("第一个for推出循环的栈>>>>>>>>>")
	printStack(iys)

	// 3. for推出，就是需要进行取出来操作符，操作数操作了
	// 找到 "="就停止
	for {
		// 碰到 = 此时操作符栈必然是没有 +-*/
		// 只是单纯的opd
		sopt = u.BackOPT(iys.GetOPT())
		if sopt == "=" {
			break
		}

		// 去除俩操作数和一个操作符进行操作
		// 多重括号，就不对了
		if err= u.CalcTopStack(iys.GetOPD(), iys.GetOPT()); err != nil {
			break
		}
	}

	// 4. 找到 = 就把一个opd弹出来 , 给 = 左边的map , = 出栈
	// 去除操作符 =
	if _, err = u.RemoveLast(iys.GetOPT()); err != nil {
		panic(err)
		return errors.New("出栈错误")
	}
	if oneVarOPD, err = u.RemoveLast(iys.GetOPD()); err != nil {
		fmt.Println("=出栈err", err)
		return err
	}
	if foneVarOPD, ok = oneVarOPD.(float64); !ok {
		return errors.New("类型转换错误")
	}
	iys.SetVar(leftVar, foneVarOPD)

	// 最后更新next
	next++
	iys.SetNext(next)

	fmt.Println("logic>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
	printStack(iys)

	return nil
}

type NullOPT struct{
	tokenValue string
}

func NewNullOPT() *NullOPT {
	return &NullOPT{}
}

func (NullOPT) InventedOpt(iys iyasuo.IYasuo) error {
	fmt.Println("遇到空格，直接下一位>>>>>>>>>>>>>>")
	printStack(iys)
	iys.SetNext(iys.GetNext() + 1)
	return nil
}

